Skip to content

19.3 实战案例

🎯 本节目标

通过一个完整的数据分析案例,展示 DeepAnalyze 的端到端工作流程。


📊 案例:学生贷款风险分析

数据集描述

本案例使用 10 个学生贷款相关的数据文件:

文件名描述字段
person.csv借款人基本信息id, name, age, income
male.xlsx性别信息id, gender
enrolled.csv在读状态id, is_enrolled
unemployed.xlsx失业状态id, is_unemployed
filed_for_bankruptcy.csv破产记录id, has_bankruptcy
no_payment_due.xlsx还款状态id, no_payment_due
loan_amount.csv贷款金额id, amount
interest_rate.xlsx利率信息id, rate
loan_term.csv贷款期限id, term_months
default_status.xlsx违约状态id, is_default

分析目标

生成一份包含以下内容的深度分析报告:

  1. 数据概览和质量评估
  2. 违约率统计分析
  3. 风险因素识别
  4. 可视化展示
  5. 结论和建议

🚀 执行过程

Step 1: 启动 DeepAnalyze

python
from deepanalyze import DeepAnalyzeVLLM

# 初始化
deepanalyze = DeepAnalyzeVLLM(
    checkpoint_path="RUC-DataLab/DeepAnalyze-8B"
)

# 设置工作目录
workspace = "/data/student_loans/"

# 分析请求
prompt = """
请分析工作目录中的学生贷款数据,生成一份完整的风险分析报告。

报告应包含:
1. 数据概览:数据质量、缺失值、基本统计
2. 违约率分析:整体违约率、不同群体违约率对比
3. 风险因素识别:找出与违约高度相关的因素
4. 可视化:关键发现的图表展示
5. 结论与建议:基于分析的风险管理建议

请确保代码可执行,图表保存到当前目录。
"""

# 执行分析
result = deepanalyze.generate(prompt, workspace)

Step 2: Agent 推理过程

以下是 DeepAnalyze 的实际推理轨迹(简化版):

轮次 1: 数据探索
─────────────────
<Analyze>
首先,我需要了解工作目录中有哪些数据文件,
并加载它们进行初步探索。
</Analyze>

<Code>
import os
import pandas as pd

# 列出工作目录中的文件
files = os.listdir('.')
print("数据文件列表:")
for f in files:
    print(f"  - {f}")
</Code>
<Execute>
数据文件列表:
  - person.csv
  - male.xlsx
  - enrolled.csv
  - unemployed.xlsx
  - filed_for_bankruptcy.csv
  - no_payment_due.xlsx
  - loan_amount.csv
  - interest_rate.xlsx
  - loan_term.csv
  - default_status.xlsx
</Execute>
轮次 2: 数据加载与合并
─────────────────────
<Understand>
工作目录包含 10 个数据文件,分为 CSV 和 Excel 格式。
我需要将它们全部加载并按 id 字段合并成一个完整的数据集。
</Understand>

<Code>
import pandas as pd

# 加载所有数据
person = pd.read_csv('person.csv')
male = pd.read_excel('male.xlsx')
enrolled = pd.read_csv('enrolled.csv')
unemployed = pd.read_excel('unemployed.xlsx')
bankruptcy = pd.read_csv('filed_for_bankruptcy.csv')
payment = pd.read_excel('no_payment_due.xlsx')
loan_amount = pd.read_csv('loan_amount.csv')
interest = pd.read_excel('interest_rate.xlsx')
term = pd.read_csv('loan_term.csv')
default_status = pd.read_excel('default_status.xlsx')

# 合并数据
dfs = [person, male, enrolled, unemployed, bankruptcy,
       payment, loan_amount, interest, term, default_status]

df = dfs[0]
for d in dfs[1:]:
    df = df.merge(d, on='id', how='left')

print(f"合并后数据集: {df.shape[0]} 行, {df.shape[1]} 列")
print("\n数据预览:")
print(df.head())
print("\n数据类型:")
print(df.dtypes)
</Code>
<Execute>
合并后数据集: 10000 行, 12 列

数据预览:
   id     name  age  income  gender  is_enrolled  ...
0   1  Alice   25   45000       0            1  ...
1   2    Bob   32   62000       1            0  ...
...

数据类型:
id                     int64
name                  object
age                    int64
income               float64
gender                 int64
is_enrolled            int64
is_unemployed          int64
has_bankruptcy         int64
no_payment_due         int64
amount               float64
rate                 float64
term_months            int64
is_default             int64
dtype: object
</Execute>
轮次 3: 数据质量评估
───────────────────
<Analyze>
现在我需要评估数据质量,检查缺失值和异常值。
</Analyze>

<Code>
# 缺失值检查
print("缺失值统计:")
print(df.isnull().sum())

# 基本统计
print("\n数值列统计:")
print(df.describe())

# 违约率
default_rate = df['is_default'].mean() * 100
print(f"\n整体违约率: {default_rate:.2f}%")
</Code>
<Execute>
缺失值统计:
id                0
name              0
age               0
income           23
gender            0
is_enrolled       0
is_unemployed     0
has_bankruptcy    0
no_payment_due    0
amount            5
rate              0
term_months       0
is_default        0
dtype: int64

数值列统计:
              age        income  ...   is_default
count  10000.000   9977.000000  ...  10000.000000
mean      35.234  52341.567890  ...      0.123400
std       12.456  28765.432100  ...      0.329012
min       18.000  12000.000000  ...      0.000000
25%       25.000  32000.000000  ...      0.000000
50%       33.000  48000.000000  ...      0.000000
75%       44.000  68000.000000  ...      0.000000
max       75.000 250000.000000  ...      1.000000

整体违约率: 12.34%
</Execute>
轮次 4-6: 风险因素分析与可视化
─────────────────────────────
<Code>
import matplotlib.pyplot as plt
import seaborn as sns

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False

# 1. 不同群体的违约率对比
fig, axes = plt.subplots(2, 2, figsize=(14, 10))

# 失业状态 vs 违约
unemployed_default = df.groupby('is_unemployed')['is_default'].mean()
axes[0,0].bar(['在职', '失业'], unemployed_default.values * 100)
axes[0,0].set_title('就业状态与违约率')
axes[0,0].set_ylabel('违约率 (%)')

# 破产记录 vs 违约
bankruptcy_default = df.groupby('has_bankruptcy')['is_default'].mean()
axes[0,1].bar(['无破产记录', '有破产记录'], bankruptcy_default.values * 100)
axes[0,1].set_title('破产记录与违约率')

# 在读状态 vs 违约
enrolled_default = df.groupby('is_enrolled')['is_default'].mean()
axes[1,0].bar(['未在读', '在读'], enrolled_default.values * 100)
axes[1,0].set_title('在读状态与违约率')
axes[1,0].set_ylabel('违约率 (%)')

# 收入分布 vs 违约
df['income_group'] = pd.cut(df['income'], bins=[0, 30000, 50000, 80000, 300000],
                            labels=['低', '中低', '中高', '高'])
income_default = df.groupby('income_group')['is_default'].mean()
axes[1,1].bar(income_default.index.astype(str), income_default.values * 100)
axes[1,1].set_title('收入水平与违约率')

plt.tight_layout()
plt.savefig('risk_factors.png', dpi=150, bbox_inches='tight')
print("风险因素分析图已保存: risk_factors.png")
</Code>
<Execute>
风险因素分析图已保存: risk_factors.png
</Execute>
轮次 7: 相关性分析
─────────────────
<Code>
# 计算各因素与违约的相关性
correlation_features = ['age', 'income', 'is_unemployed', 'has_bankruptcy',
                       'is_enrolled', 'no_payment_due', 'amount', 'rate', 'term_months']

correlations = {}
for feature in correlation_features:
    if feature in df.columns:
        corr = df[feature].corr(df['is_default'])
        correlations[feature] = corr

# 按相关性排序
sorted_corr = sorted(correlations.items(), key=lambda x: abs(x[1]), reverse=True)

print("与违约的相关性排名:")
print("-" * 40)
for feature, corr in sorted_corr:
    direction = "正相关" if corr > 0 else "负相关"
    print(f"{feature:20s}: {corr:+.4f} ({direction})")
</Code>
<Execute>
与违约的相关性排名:
----------------------------------------
has_bankruptcy      : +0.3521 (正相关)
is_unemployed       : +0.2876 (正相关)
no_payment_due      : -0.2234 (负相关)
income              : -0.1987 (负相关)
rate                : +0.1543 (正相关)
amount              : +0.0987 (正相关)
term_months         : +0.0654 (正相关)
is_enrolled         : -0.0432 (负相关)
age                 : -0.0321 (负相关)
</Execute>
轮次 8: 生成最终报告
───────────────────
<Answer>
# 学生贷款风险分析报告

## 摘要

本报告分析了 10,000 条学生贷款记录,整体违约率为 **12.34%**。
通过多维度分析,识别出了影响违约的关键风险因素。

---

## 1. 数据概览

### 1.1 数据集规模
- **总记录数**: 10,000 条
- **特征数量**: 12 个
- **违约样本**: 1,234 条 (12.34%)

### 1.2 数据质量
- 收入字段有 23 条缺失值 (0.23%)
- 贷款金额有 5 条缺失值 (0.05%)
- 整体数据质量良好

---

## 2. 违约率分析

### 2.1 整体违约率
**12.34%** 的借款人出现违约

### 2.2 分群违约率对比

| 群体 | 违约率 | 相对风险 |
|------|--------|---------|
| 有破产记录 | 38.5% | 3.1x |
| 失业状态 | 29.7% | 2.4x |
| 低收入群体 | 21.3% | 1.7x |
| 高利率贷款 | 18.9% | 1.5x |

![风险因素分析](./risk_factors.png)

---

## 3. 关键风险因素

### 3.1 相关性分析结果

按与违约相关性强度排序:

1. **破产记录** (r = +0.35): 最强风险信号
2. **失业状态** (r = +0.29): 还款能力直接影响
3. **还款记录** (r = -0.22): 良好记录降低风险
4. **收入水平** (r = -0.20): 高收入降低违约

### 3.2 风险因素解读

- **破产记录**是违约的最强预测因子
- **就业状态**显著影响还款能力
- **历史还款记录**是可靠的信用指标

---

## 4. 结论与建议

### 4.1 主要发现

1. 破产记录和失业状态是两个最重要的风险指标
2. 收入与违约呈负相关,高收入群体违约率更低
3. 良好的还款记录能有效降低违约风险

### 4.2 风险管理建议

1. **审批策略**
   - 对有破产记录的申请人加强审核
   - 建立收入验证机制

2. **贷后管理**
   - 对失业借款人提供还款宽限期
   - 建立早期预警系统

3. **产品设计**
   - 考虑根据风险水平差异化定价
   - 提供灵活还款选项

---

*报告生成时间: 2025-01-15*
*分析工具: DeepAnalyze v1.0*
</Answer>

📊 生成的可视化

分析报告示例

图:DeepAnalyze 生成的分析报告示例


📈 执行统计

指标
总轮次8 轮
代码块数7 个
执行时间~180 秒
生成图表2 个
报告字数~800 字

🔍 与 LangGraph Agent 的对比

如果使用 LangGraph 实现相同的分析任务,代码结构会有很大不同:

LangGraph 版本(示意)

python
from langgraph.graph import StateGraph
from langgraph.prebuilt import create_react_agent

# 定义工具
@tool
def load_csv(filename: str) -> str:
    """加载 CSV 文件"""
    df = pd.read_csv(filename)
    return df.head().to_string()

@tool
def run_python(code: str) -> str:
    """执行 Python 代码"""
    exec(code)
    return "执行完成"

@tool
def save_plot(filename: str) -> str:
    """保存当前图表"""
    plt.savefig(filename)
    return f"已保存: {filename}"

# 创建 Agent
tools = [load_csv, run_python, save_plot]
agent = create_react_agent(llm, tools)

# 执行
result = agent.invoke({
    "messages": [{"role": "user", "content": prompt}]
})

关键差异

维度DeepAnalyzeLangGraph
工具定义隐式(代码执行)显式(@tool 装饰器)
执行控制<Code> 标签tool_calls API
状态管理消息列表TypedDict State
可扩展性需重新训练添加工具即可
专业性数据科学专用通用任务

💡 实践建议

何时使用 DeepAnalyze

适合场景:

  • 标准化的数据分析流程
  • 需要生成报告的任务
  • 对数据隐私有要求(本地部署)
  • 批量处理类似任务

不适合场景:

  • 需要调用外部 API
  • 需要与数据库交互
  • 需要实时数据处理
  • 需要多模态处理

优化技巧

  1. 清晰的 Prompt

    • 明确列出分析目标
    • 指定输出格式要求
    • 提供必要的背景信息
  2. 数据准备

    • 确保文件格式正确
    • 提供数据字典说明
    • 预处理明显的问题
  3. 结果验证

    • 检查生成的代码逻辑
    • 验证统计结果的合理性
    • 审核可视化的准确性

接下来: 19.4 本章小结

基于 MIT 许可证发布。内容版权归作者所有。